package com.analysis.utils;

import com.analysis.entity.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 基于Redis的会话管理器
 * 管理用户登录状态和会话信息
 */
@Component
public class RedisSessionManager {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    // 会话信息类
    private static class SessionInfo {
        private User user;
        private LocalDateTime createTime;
        private LocalDateTime lastAccessTime;
        
        public SessionInfo() {}
        
        public SessionInfo(User user) {
            this.user = user;
            this.createTime = LocalDateTime.now();
            this.lastAccessTime = LocalDateTime.now();
        }
        
        public User getUser() {
            return user;
        }
        
        public void setUser(User user) {
            this.user = user;
        }
        
        public LocalDateTime getCreateTime() {
            return createTime;
        }
        
        public void setCreateTime(LocalDateTime createTime) {
            this.createTime = createTime;
        }
        
        public LocalDateTime getLastAccessTime() {
            return lastAccessTime;
        }
        
        public void setLastAccessTime(LocalDateTime lastAccessTime) {
            this.lastAccessTime = lastAccessTime;
        }
        
        public void updateLastAccessTime() {
            this.lastAccessTime = LocalDateTime.now();
        }
        
        public boolean isExpired(int expireDays) {
            return lastAccessTime.isBefore(LocalDateTime.now().minusDays(expireDays));
        }
    }
    
    // Redis键前缀
    private static final String SESSION_PREFIX = "session:";
    private static final String USER_TOKEN_PREFIX = "user_token:";
    private static final String SESSION_STATS_KEY = "session_stats";
    
    // 会话过期时间（天）
    private static final int SESSION_EXPIRE_DAYS = 30;
    
    // Redis过期时间（秒）- 30天
    private static final long REDIS_EXPIRE_SECONDS = 30 * 24 * 60 * 60;
    
    /**
     * 用户登录，创建会话
     */
    public String createSession(User user) {
        try {
            // 如果用户已经登录，先清除旧会话
            String oldToken = getTokenByUserId(user.getId());
            if (oldToken != null) {
                removeSession(oldToken);
            }
            
            // 生成新的token
            String token = generateToken();
            
            // 创建会话信息
            SessionInfo sessionInfo = new SessionInfo(user);
            
            // 存储到Redis
            String sessionKey = SESSION_PREFIX + token;
            String userTokenKey = USER_TOKEN_PREFIX + user.getId();
            
            // 序列化会话信息
            String sessionJson = objectMapper.writeValueAsString(sessionInfo);
            
            // 存储会话信息，设置过期时间
            redisTemplate.opsForValue().set(sessionKey, sessionJson, REDIS_EXPIRE_SECONDS, TimeUnit.SECONDS);
            redisTemplate.opsForValue().set(userTokenKey, token, REDIS_EXPIRE_SECONDS, TimeUnit.SECONDS);
            
            return token;
        } catch (JsonProcessingException e) {
            throw new RuntimeException("创建会话失败", e);
        }
    }
    
    /**
     * 根据token获取用户信息
     */
    public User getUserByToken(String token) {
        try {
            String sessionKey = SESSION_PREFIX + token;
            String sessionJson = (String) redisTemplate.opsForValue().get(sessionKey);
            
            if (sessionJson == null) {
                return null;
            }
            
            // 反序列化会话信息
            SessionInfo sessionInfo = objectMapper.readValue(sessionJson, SessionInfo.class);
            
            // 检查会话是否过期
            if (sessionInfo.isExpired(SESSION_EXPIRE_DAYS)) {
                // 会话过期，清除会话
                removeSession(token);
                return null;
            }
            
            // 更新最后访问时间
            sessionInfo.updateLastAccessTime();
            
            // 更新Redis中的会话信息
            String updatedSessionJson = objectMapper.writeValueAsString(sessionInfo);
            redisTemplate.opsForValue().set(sessionKey, updatedSessionJson, REDIS_EXPIRE_SECONDS, TimeUnit.SECONDS);
            
            return sessionInfo.getUser();
        } catch (JsonProcessingException e) {
            throw new RuntimeException("获取用户信息失败", e);
        }
    }
    
    /**
     * 根据用户ID获取token
     */
    public String getTokenByUserId(Long userId) {
        String userTokenKey = USER_TOKEN_PREFIX + userId;
        return (String) redisTemplate.opsForValue().get(userTokenKey);
    }
    
    /**
     * 验证token是否有效
     */
    public boolean isValidToken(String token) {
        if (token == null) {
            return false;
        }
        
        try {
            String sessionKey = SESSION_PREFIX + token;
            String sessionJson = (String) redisTemplate.opsForValue().get(sessionKey);
            
            if (sessionJson == null) {
                return false;
            }
            
            // 反序列化会话信息
            SessionInfo sessionInfo = objectMapper.readValue(sessionJson, SessionInfo.class);
            
            // 检查会话是否过期
            if (sessionInfo.isExpired(SESSION_EXPIRE_DAYS)) {
                // 会话过期，清除会话
                removeSession(token);
                return false;
            }
            
            // 更新最后访问时间
            sessionInfo.updateLastAccessTime();
            
            // 更新Redis中的会话信息
            String updatedSessionJson = objectMapper.writeValueAsString(sessionInfo);
            redisTemplate.opsForValue().set(sessionKey, updatedSessionJson, REDIS_EXPIRE_SECONDS, TimeUnit.SECONDS);
            
            return true;
        } catch (JsonProcessingException e) {
            return false;
        }
    }
    
    /**
     * 用户登出，清除会话
     */
    public void removeSession(String token) {
        try {
            String sessionKey = SESSION_PREFIX + token;
            String sessionJson = (String) redisTemplate.opsForValue().get(sessionKey);
            
            if (sessionJson != null) {
                // 反序列化获取用户信息
                SessionInfo sessionInfo = objectMapper.readValue(sessionJson, SessionInfo.class);
                User user = sessionInfo.getUser();
                
                // 删除会话信息
                redisTemplate.delete(sessionKey);
                
                // 删除用户token映射
                if (user != null) {
                    String userTokenKey = USER_TOKEN_PREFIX + user.getId();
                    redisTemplate.delete(userTokenKey);
                }
            }
        } catch (JsonProcessingException e) {
            // 如果反序列化失败，直接删除key
            String sessionKey = SESSION_PREFIX + token;
            redisTemplate.delete(sessionKey);
        }
    }
    
    /**
     * 根据用户ID登出
     */
    public void removeSessionByUserId(Long userId) {
        String token = getTokenByUserId(userId);
        if (token != null) {
            removeSession(token);
        }
    }
    
    /**
     * 清除所有会话
     */
    public void clearAllSessions() {
        // 删除所有会话相关的key
        Set<String> sessionKeys = redisTemplate.keys(SESSION_PREFIX + "*");
        Set<String> userTokenKeys = redisTemplate.keys(USER_TOKEN_PREFIX + "*");
        
        if (sessionKeys != null && !sessionKeys.isEmpty()) {
            redisTemplate.delete(sessionKeys);
        }
        if (userTokenKeys != null && !userTokenKeys.isEmpty()) {
            redisTemplate.delete(userTokenKeys);
        }
    }
    
    /**
     * 获取当前在线用户数量
     */
    public int getOnlineUserCount() {
        Set<String> sessionKeys = redisTemplate.keys(SESSION_PREFIX + "*");
        return sessionKeys != null ? sessionKeys.size() : 0;
    }
    
    /**
     * 生成token
     */
    private String generateToken() {
        return "token_" + UUID.randomUUID().toString().replace("-", "");
    }
    
    /**
     * 刷新token（延长会话时间）
     */
    public String refreshToken(String oldToken) {
        try {
            String sessionKey = SESSION_PREFIX + oldToken;
            String sessionJson = (String) redisTemplate.opsForValue().get(sessionKey);
            
            if (sessionJson == null) {
                return null;
            }
            
            // 反序列化会话信息
            SessionInfo sessionInfo = objectMapper.readValue(sessionJson, SessionInfo.class);
            
            // 检查会话是否过期
            if (sessionInfo.isExpired(SESSION_EXPIRE_DAYS)) {
                // 会话过期，清除会话
                removeSession(oldToken);
                return null;
            }
            
            // 创建新token
            String newToken = generateToken();
            User user = sessionInfo.getUser();
            
            // 删除旧会话
            removeSession(oldToken);
            
            // 创建新会话
            createSession(user);
            
            return newToken;
        } catch (JsonProcessingException e) {
            throw new RuntimeException("刷新Token失败", e);
        }
    }
    
    /**
     * 定时清理过期会话
     * 每小时执行一次
     */
    @Scheduled(fixedRate = 3600000) // 1小时 = 3600000毫秒
    public void cleanExpiredSessions() {
        try {
            Set<String> sessionKeys = redisTemplate.keys(SESSION_PREFIX + "*");
            if (sessionKeys == null || sessionKeys.isEmpty()) {
                return;
            }
            
            int cleanedCount = 0;
            for (String sessionKey : sessionKeys) {
                String sessionJson = (String) redisTemplate.opsForValue().get(sessionKey);
                if (sessionJson != null) {
                    try {
                        SessionInfo sessionInfo = objectMapper.readValue(sessionJson, SessionInfo.class);
                        if (sessionInfo.isExpired(SESSION_EXPIRE_DAYS)) {
                            // 删除过期会话
                            redisTemplate.delete(sessionKey);
                            
                            // 删除对应的用户token映射
                            User user = sessionInfo.getUser();
                            if (user != null) {
                                String userTokenKey = USER_TOKEN_PREFIX + user.getId();
                                redisTemplate.delete(userTokenKey);
                            }
                            
                            cleanedCount++;
                        }
                    } catch (JsonProcessingException e) {
                        // 如果反序列化失败，删除这个key
                        redisTemplate.delete(sessionKey);
                        cleanedCount++;
                    }
                }
            }
            
            System.out.println("Redis会话清理完成，清理了 " + cleanedCount + " 个过期会话，当前在线用户数: " + getOnlineUserCount());
        } catch (Exception e) {
            System.err.println("清理过期会话时发生错误: " + e.getMessage());
        }
    }
    
    /**
     * 获取会话统计信息
     */
    public String getSessionStats() {
        int totalSessions = getOnlineUserCount();
        int activeUsers = totalSessions; // 在Redis实现中，会话数等于活跃用户数
        
        StringBuilder stats = new StringBuilder();
        stats.append("Redis会话统计信息:\n");
        stats.append("总会话数: ").append(totalSessions).append("\n");
        stats.append("活跃用户数: ").append(activeUsers).append("\n");
        stats.append("会话过期时间: ").append(SESSION_EXPIRE_DAYS).append("天\n");
        stats.append("Redis过期时间: ").append(REDIS_EXPIRE_SECONDS / 86400).append("天\n");
        
        return stats.toString();
    }
    
    /**
     * 获取Redis连接信息
     */
    public String getRedisInfo() {
        try {
            StringBuilder info = new StringBuilder();
            info.append("Redis连接信息:\n");
            
            // 获取Redis连接工厂信息
            RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory();
            if (connectionFactory != null) {
                info.append("连接工厂类型: ").append(connectionFactory.getClass().getSimpleName()).append("\n");
                
                // 测试连接
                try {
                    redisTemplate.opsForValue().set("redis_test_key", "test_value", 10, TimeUnit.SECONDS);
                    String testValue = (String) redisTemplate.opsForValue().get("redis_test_key");
                    if ("test_value".equals(testValue)) {
                        info.append("连接状态: 正常\n");
                        redisTemplate.delete("redis_test_key");
                    } else {
                        info.append("连接状态: 异常\n");
                    }
                } catch (Exception e) {
                    info.append("连接状态: 异常 - ").append(e.getMessage()).append("\n");
                }
            } else {
                info.append("连接工厂: 未配置\n");
            }
            
            // 获取当前在线用户数
            int onlineCount = getOnlineUserCount();
            info.append("当前在线用户数: ").append(onlineCount).append("\n");
            
            // 获取Redis键数量
            try {
                Set<String> allKeys = redisTemplate.keys("*");
                int keyCount = allKeys != null ? allKeys.size() : 0;
                info.append("Redis键总数: ").append(keyCount).append("\n");
            } catch (Exception e) {
                info.append("Redis键总数: 无法获取 - ").append(e.getMessage()).append("\n");
            }
            
            return info.toString();
        } catch (Exception e) {
            return "获取Redis信息失败: " + e.getMessage();
        }
    }
}
